package pri.black.dogview.controller;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import pri.black.dogview.domain.*;
import pri.black.dogview.domain.dto.AddressInfo;
import pri.black.dogview.domain.vo.DeviceLocationCycle;
import pri.black.dogview.exception.BizException;
import pri.black.dogview.mapper.GpsDataMapper;
import pri.black.dogview.service.*;

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@RestController
public class ApiController {

    @Autowired
    private IDeviceGpsLogService deviceGpsLogService;

    @Autowired
    private IDeviceStatusService deviceStatusService;

    @Autowired
    private IDeviceService deviceService;

    @Autowired
    private IDeviceLogsService deviceLogsService;

    @Autowired
    private DriverService driverService;


    private String key(String lng, String lat) {
        int rate = 4;
        return lng.substring(0, 3 + rate) + "," + lat.substring(0, 2 + rate);
    }

    @GetMapping("/dogs-location")
    R dogLocation(@RequestParam(value = "queryTime",required = false)String queryTime) {

        if (StringUtils.hasLength(queryTime)) {
            LocalDate queryDate = LocalDate.parse(queryTime, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            LocalDateTime startTime = LocalDateTime.of(queryDate, LocalTime.of(0, 0, 0));
            LocalDateTime endTime = startTime.plusDays(1);
            List<DeviceGpsLog> list = deviceGpsLogService.lambdaQuery()
                    .lt(DeviceGpsLog::getCreateTime, endTime)
                    .gt(DeviceGpsLog::getCreateTime, startTime)
                    .orderByAsc(DeviceGpsLog::getId)
                    .list();
            List<DeviceGpsLog> tmep = new LinkedList<>();
            String last = "";
            String temps;
            for (DeviceGpsLog deviceGpsLog : list) {
                temps = "ll" + deviceGpsLog.getLongitude() + deviceGpsLog.getLatitude();
                if (temps.equals(last)) {
                    continue;
                }else {
                    last = temps;
                }
                tmep.add(deviceGpsLog);
            }
            return R.ok(tmep);
        }else {
            List<DeviceGpsLog> list = deviceGpsLogService.lambdaQuery()
                    .orderByDesc(DeviceGpsLog::getId)
                    .last("limit 1000")
                    .list();
            List<DeviceGpsLog> tmep = new LinkedList<>();
            String last = "";
            String temps;
//            for (DeviceGpsLog deviceGpsLog : list) {
            for (int i= list.size() - 1; i >=0  ;i -- ){
                DeviceGpsLog deviceGpsLog = list.get(i);
                temps = "ll" + deviceGpsLog.getLongitude() + deviceGpsLog.getLatitude();
                if (temps.equals(last)) {
                    continue;
                }else {
                    last = temps;
                }
                tmep.add(deviceGpsLog);
            }
            return R.ok(tmep);
        }
    }

    @GetMapping("/dogs-status")
    R dogStatus(Model model) {
        List<DeviceStatus> list = deviceStatusService.lambdaQuery().orderByDesc(DeviceStatus::getId).list();
        return R.ok(list);
    }

    @GetMapping("device/list")
    R deviceLlist() {
        return R.ok(deviceService.list());
    }

    @GetMapping("device/page/list")
    R devicePageList(Page<Device> devicePage) {
        Page<Device> page = deviceService.page(devicePage);
        return R.ok(page);
    }

    @PostMapping("device")
    R postDevice(@RequestBody Device device){
        deviceService.save(device);
        return R.ok();
    }

    @PutMapping("device")
    R putDevice(@RequestBody Device device){
        if (device.getId() == null) {
            throw new BizException("ID不能为空");
        }
        deviceService.updateById(device);
        return R.ok();
    }

    @GetMapping("counts/{type}")
    R counts(@PathVariable("type") String type) {
        switch (type) {
            case "device":
                return R.ok(deviceService.count());
            case "log":
                return R.ok(deviceStatusService.count());
            case "location":
                return R.ok(deviceGpsLogService.count());
            case "restart":
                return R.ok(deviceStatusService.lambdaQuery().eq(DeviceStatus::getTicks, 0).count());
        }

        return R.fail();
    }

    @GetMapping("table-data/{type}")
    R tabledata(@PathVariable("type") String type) {
        switch (type) {
            case "log" -> {
                return R.ok(deviceStatusService.dateCount());
            }
            case "battery" -> {
                return R.ok(deviceStatusService.batteryCount());
            }
            case "location" -> {
                return R.ok(deviceGpsLogService.dateCount());
            }
        }
        return R.fail();
    }

    @GetMapping("device-location-cycle/list")
    R deviceLocationCycleList(){
        List<DeviceStatus> list = deviceStatusService.lambdaQuery().eq(DeviceStatus::getTicks, 0).list();
        int size = list.size();
        List<DeviceLocationCycle> cycles = new LinkedList<>();
        for (int i = 0; i < list.size(); i++) {
            DeviceStatus deviceStatus = list.get(i);
            DeviceStatus next = i + 1 == size ? null : list.get(i + 1);
            if (next != null) {
                next = deviceStatusService.getById(next.getId() - 1);
            }else {
                next = deviceStatusService.lambdaQuery().orderByDesc(DeviceStatus::getId).last("limit 1").one();
            }

            DeviceLocationCycle cycle = new DeviceLocationCycle();
            cycle.setStartTicksStatusId(deviceStatus.getId());
            cycle.setStartTime(deviceStatus.getUpdateTime());
            cycle.setEndTime(next.getUpdateTime());
            Duration between = Duration.between(cycle.getStartTime(), cycle.getEndTime());
            long seconds = between.getSeconds();
            String durationString = String.format("%d小时%d分%d秒", seconds / 3600, seconds % 3600 / 60, seconds % 3600 % 60);
            cycle.setDuration(seconds);
            cycle.setHDuration(durationString);
            cycles.add(cycle);
        }
        cycles = cycles.stream().filter(e -> e.getDuration() != 0).toList();
        ArrayList<DeviceLocationCycle> deviceStatuses = new ArrayList<>();
        deviceStatuses.addAll(cycles);
        deviceStatuses.sort((a,b) -> b.getStartTicksStatusId().intValue() - a.getStartTicksStatusId().intValue());
        return R.ok(deviceStatuses.subList(0,10));
    }

    @GetMapping("logs-page")
    R logsPage(Page<DeviceLogs> query,
               @RequestParam(value = "startTime",required = false) String startTime,
               @RequestParam(value = "endTime",required = false) String endTime) {
        Page<DeviceLogs> page = deviceLogsService.lambdaQuery()
                .gt(StringUtils.hasLength(startTime), DeviceLogs::getCreateTime, startTime)
                .lt(StringUtils.hasLength(endTime), DeviceLogs::getCreateTime, endTime)
                .orderByDesc(DeviceLogs::getId)
                .page(query);
        return R.ok(page);
    }

    @GetMapping("locations/list")
    R locationList(Page<DeviceGpsLog> query,DeviceGpsLog logQuery,
                   @RequestParam(value = "startTime",required = false) String startTime,
                   @RequestParam(value = "endTime",required = false) String endTime){
        Page<DeviceGpsLog> page = deviceGpsLogService.lambdaQuery()
                .eq(logQuery.getSource() != null, DeviceGpsLog::getSource, logQuery.getSource())
                .gt(StringUtils.hasLength(startTime), DeviceGpsLog::getCreateTime, startTime)
                .lt(StringUtils.hasLength(endTime), DeviceGpsLog::getCreateTime, endTime)
                .orderByDesc(DeviceGpsLog::getId).page(query);
        return R.ok(page);
    }

    @GetMapping("devicestatus/list")
    R deviceStatusList(Page<DeviceStatus> query,DeviceGpsLog logQuery,
                   @RequestParam(value = "startTime",required = false) String startTime,
                   @RequestParam(value = "endTime",required = false) String endTime){
        Page<DeviceStatus> page = deviceStatusService.lambdaQuery()
                .gt(StringUtils.hasLength(startTime), DeviceStatus::getUpdateTime, startTime)
                .lt(StringUtils.hasLength(endTime), DeviceStatus::getUpdateTime, endTime)
                .orderByDesc(DeviceStatus::getId).page(query);
        return R.ok(page);
    }

    @GetMapping("trace/items")
    R trace(){
        return R.ok(deviceLogsService.queryTraceData());
    }

    @GetMapping("trace/logs")
    R traceLogs(
            @RequestParam(value = "start",required = false) String start,
            @RequestParam(value = "end",required = false) String end
    ) {

        List<DeviceGpsLog> gpslogs = deviceGpsLogService.query(start, end);
        return driverService.doIt(gpslogs);
    }

}
